package com.ai_chat.sys.controller;

import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.ai_chat.common.util.JwtUtil;
import com.ai_chat.common.vo.CodeType;
import com.ai_chat.common.vo.Result;
import com.ai_chat.sys.entity.EmailDTO;
import com.ai_chat.sys.entity.RegistrationDTO;
import com.ai_chat.sys.entity.User;
import com.ai_chat.sys.entity.WeChatUser;
import com.ai_chat.sys.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {

    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private JwtUtil jwtUtil;

    private Map<Integer, Optional<SseEmitter>> sseEmitterMap = new ConcurrentHashMap<>();


    //验证码
    @PostMapping("/sendVerificationCode")
    public Result<Map<String,Object>> sendVerificationCode(@RequestBody EmailDTO emailDTO){
        int resultCode = userService.sendVerificationCode(emailDTO.getEmail());

        if(resultCode == CodeType.OK)
            return Result.success();
        else
            return Result.fail(resultCode);
    }

    //注册
    @PostMapping("/register")
    public Result<Map<String,Object>> register(@RequestBody RegistrationDTO registrationDTO){
        Integer resultCode = userService.register(registrationDTO);

        if(resultCode == CodeType.OK){
            return Result.success();
        }
        return Result.fail(resultCode);

    }


    @PostMapping("/login")
    public Result<Map<String,Object>> login(@RequestBody User user){
        Map<String,Object> data = userService.login(user);

        if(data != null){
            return Result.success(data);
        }

        return Result.fail(CodeType.WRONG_EMAIL_OR_PASSWORD);
    }



    //微信接入测试接口
    @GetMapping("/wechatTest")
    public String wechat(
            @RequestParam(value = "signature") String signature,
            @RequestParam(value = "timestamp") String timestamp,
            @RequestParam(value = "nonce") String nonce,
            @RequestParam(value = "echostr") String echostr){
        ArrayList<String> list=new ArrayList<String>();
        list.add(nonce);
        list.add(timestamp);
        list.add("ai_chat666");

        Collections.sort(list);

        String data = list.get(0)+list.get(1)+list.get(2);

        MessageDigest md;
        String hashedData;
        try {
            md = MessageDigest.getInstance("SHA-1");
            byte[] hashedBytes = md.digest(data.getBytes());

            StringBuilder hexString = new StringBuilder();
            for (byte b : hashedBytes) {
                String hex = Integer.toHexString(0xFF & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            hashedData = hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }

        if(hashedData.equals(signature))
            return echostr;
        else
            return "";
    }


    @GetMapping("/wechatQrCode")
    public Result<Map<String,Object>> wechatQrCode(){
        Map<String,Object> data = new HashMap<>();

        String redirectUri;
        try {
            //回调地址，做urlEncode
            redirectUri = URLEncoder.encode("http://repcsz.natappfree.cc/user/wechatNotify","UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        //产生一个随机值，来作为前端唯一标识符。
        //不能太大，不然前端存储时存在精度损失，因为前端对于数字的存储全部采用的double双精度浮点数，最大安全整数为9kw亿左右。
        Random random = new Random();
        Integer ret;
        while(true)
        {
            ret = random.nextInt(0, Integer.MAX_VALUE);
            if(!sseEmitterMap.containsKey(ret)){
                //放进去一个空值占位，避免后续又重复产生了这个值，导致无法唯一标识
                sseEmitterMap.put(ret, Optional.empty());
                break;
            }
        }

        //二维码链接地址
        String qrcodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx317d50ff8442777d&redirect_uri="
                + redirectUri +  "&response_type=code&scope=snsapi_userinfo&state=" + ret + "#wechat_redirect";

        QrConfig config = new QrConfig();
        config.setWidth(300);
        config.setHeight(300);
        //为了将二维码和后端产生的对前端的唯一标识都返回过去，二维码要转成base64编码，从二进制变成字符串。
        String base64Img = QrCodeUtil.generateAsBase64(qrcodeUrl,config,"jpg");

        data.put("qrcode",base64Img);
        data.put("sseEmitterId",ret);

        return Result.success(data);
    }



    //微信回调接口
    @GetMapping("/wechatNotify")
    public void wechatNotify(@RequestParam(value = "code") String code,@RequestParam(value = "state") String state){
        WeChatUser user = userService.getWechatUserInfo(code);

        sseSend(Integer.parseInt(state), user);
    }

    private void sseSend(Integer state, WeChatUser user){
        //state就是前端标识
        Optional<SseEmitter> optional = sseEmitterMap.get(state);

        //确保sse通信建立完成
        while(optional.isEmpty()){
            // 如果还没有找到，等待一段时间再试
            try {
                Thread.sleep(2000); // 等待2秒
                optional = sseEmitterMap.get(state);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        try {
            SseEmitter emitter = optional.get();
            emitter.send(SseEmitter.event().data(user));

            emitter.complete();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    //前端请求和后端建立sse通信管道，并通过路径参数将前端对应的唯一标识传过来。
    @GetMapping(value = "/createSse/{sseEmitterId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter createSseConnect(@PathVariable("sseEmitterId") Integer id){

        //默认是30s有效时间，0为一直有效
        SseEmitter sseEmitter = new SseEmitter(0L);

        System.out.println("调用SSE Connection");
        sseEmitterMap.put(id,Optional.of(sseEmitter));
        sseEmitter.onCompletion(()-> {
            sseEmitterMap.remove(id);
        });

        return sseEmitter;
    }





    @PostMapping("/wechatTryLogin")
    public Result<Map<String,Object>> wechatTryLogin(@RequestBody User user){

        Map<String,Object> token =  userService.wechatTryLogin(user);

        if(token != null){
            return Result.success(token);
        }
        return Result.fail(CodeType.WECHAT_ACCOUNT_NOT_BIND);
    }


    //已有AI_CHAT账号，做绑定。成功绑定即可登录。
    @PostMapping("/wechatBindWithHasAccount")
    public Result<Map<String,Object>> wechatBindWithHasAccount(@RequestBody User user){

        //更新openid字段从null变成现在的openid
        Map<String,Object> data = userService.wechatBindWithHasAccount(user);

        if(data != null){
            return Result.success(data);
        }
        else{
            return Result.fail(CodeType.WECHAT_BIND_FAIL);
        }
    }



    @GetMapping("/query")
    public Result<Map<String,Object>> query(@RequestHeader("Authorization") String token){
        User user;
        try{
            user = jwtUtil.parseToken(token, User.class);
        }catch (Exception e){
            e.printStackTrace();
            return Result.fail(CodeType.TOKEN_EXPIRED_OR_INVALID);
        }
        Map<String,Object> data=userService.query(user.getId());

        if(data != null){
            return Result.success(data);
        }
        return Result.fail(CodeType.WECHAT_ACCOUNT_NOT_BIND);
    }


    @PostMapping("/editUserNickName")
    public Result<Map<String,Object>> editUserNickName(@RequestHeader("Authorization") String token,@RequestBody Map<String,String> requesyBody){
        User user;
        try{
            user = jwtUtil.parseToken(token, User.class);
        }catch (Exception e){
            e.printStackTrace();
            return Result.fail(CodeType.TOKEN_EXPIRED_OR_INVALID);
        }
        String nickname=requesyBody.get("nickname");
        userService.editUserNickName(user.getId(),nickname);
        return Result.success();



    }


    @PostMapping("/editUserPassword")
    public Result<Map<String,Object>> editUserPassword(@RequestHeader("Authorization") String token,@RequestBody Map<String,String> requesyBody){
        User user;
        try{
            user = jwtUtil.parseToken(token, User.class);
        }catch (Exception e){
            e.printStackTrace();
            return Result.fail(CodeType.TOKEN_EXPIRED_OR_INVALID);
        }
        String prepassword=requesyBody.get("password");
        String newpassword=requesyBody.get("newPassword");
        if(!userService.PsEqual(user.getId(),prepassword)){
            return Result.fail(CodeType.ORIGINAL_PASSWORD_INCORRECT);
        }
        userService.editUserPassword(user.getId(),newpassword);
        return Result.success();

    }



}